#include"mystdio.h"
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<malloc.h>
#include<unistd.h>
#include<assert.h>


MY_FILE* my_fopen(const char* path,const char *mode)//模拟实现fopen          
{
  //首先辨别打开文件的模式
  int flag=0;
  if(strcmp(mode,"r")==0) flag |= O_RDONLY;
  else if(strcmp(mode,"w")==0)  flag |= (O_CREAT|O_WRONLY|O_TRUNC);
  else if(strcmp(mode,"a")==0)  flag |= (O_CREAT|O_WRONLY|O_APPEND);
  else{
    //其他模式 r+、w+、a+
  }

  //创建文件或打开文件
  mode_t m=0666;
  int fd=0;
  if(flag&O_CREAT) fd=open(path,flag,m);//创建文件
  else fd=open(path,flag);//打开文件

  //返回MY_FILE对象，需要先构建
  MY_FILE * mf=(MY_FILE*)malloc(sizeof(MY_FILE));
  if(mf==NULL)
  {
    close(fd);
    return NULL;
  }

  //初始化MY_FILE对象
  mf->fd=fd;
  mf->flags=0;//清零
  mf->flags=BUFF_LINE;//简单实现，实际上需要识别终端判断刷新类型
  //mf->outputbuffer[0]=0;//初始化缓冲区
  memset(mf->outputbuffer,'\0',sizeof(mf->outputbuffer));
  mf->current=0;
  //返回打开的文件
  return mf;
}

//size是单个单元的大小，nmemb是单个单元的数量
size_t my_fwrite(const void* ptr,size_t size, size_t nmemb,MY_FILE* stream)//模    拟实现fwrite
{
  //如果缓冲区已经满了，则想刷新缓冲区
  if(stream->current==NUM) my_fflush(stream);

  //根据缓冲区剩余空间情况，进行拷贝
  size_t user_size=size*nmemb;//用户数据大小
  size_t my_size=NUM - stream->current;//缓冲区剩余空间大小
  size_t writen=0;//有效写入缓冲区长度
  if(my_size>=user_size)
  {
    memcpy(stream->outputbuffer+stream->current,ptr,user_size);//将用户数据拷贝至缓冲区
    stream->current+=user_size;
    writen=user_size;
  }
  else
  {
    memcpy(stream->outputbuffer+stream->current,ptr,my_size);
    //更新计数器
    stream->current+=my_size;
    writen=my_size;
  }

  //刷新
  //如果不发生刷新，就是不进行写入，也就是不进行IO，没有系统调用
  //所以my_fwrite函数调用非常快，数据会暂时保存在缓冲区中
  //可以在缓冲区中积压多份数据，统一进行刷新写入，本质上就是一次IO可以处理更多数据，提高IO效率
  if(stream->flags&BUFF_ALL)//全刷新
  {
    if(stream->current==NUM) my_fflush(stream);
  }
  else if(stream->flags&BUFF_LINE)//行刷新
  {
    if(stream->outputbuffer[stream->current-1]=='\n') my_fflush(stream);
  }
  else
  {

  }
  
  return writen;
}


int my_fflush(MY_FILE* fp)//用于刷新缓冲区，相当于C库中的fflush
{
  assert(fp);
  write(fp->fd,fp->outputbuffer,fp->current);//将缓冲区数据通过系统调用接口拷贝给OS，从fd文件描述符中读取current个内容，拷贝到outputbuffer中
  fp->current=0;//代表缓冲区清空
  fsync(fp->fd);//系统调用接口，强制刷新缓冲区内容至文件
  return 0;
}

int my_fclose(MY_FILE* fp)//模拟实现fclose  
{
  assert(fp);
  //冲刷缓冲区
  if(fp->current > 0) my_fflush(fp);
  //关闭文件
  close(fp->fd);
  //释放堆空间
  free(fp);
  //将指针置NULL
  fp=NULL;
  return 0;
}

//int my_printf(const char* format,...)//可变参数
//{
//  //首先要获取对应的变量
//  //定义缓冲区，将变量转换成字符串
//  //调用fwrite实现输出
//  //将字符串内容拷贝到stdout的缓冲区buffer
//  //结合刷新策略显示即可
//}




